
// 类型保护就是一些表达式，他们在编译的时候就能通过类型信息确保某个作用域内变量的类型
// 类型保护就是能够通过关键字判断出分支中的类型
export {}
// 1.typeof保护
namespace a {
    function Fn ( a:string | number ){
        if(typeof a === 'string'){}
        if(typeof a === 'number'){}
    }
}
// 2.instanceof类型保护
namespace b {
    class A {}
    class B extends A {}
    function Fn (a:A){
        if(a instanceof B){}else{}
    }
}


// 3.可辨识的联合类型
namespace c {
    interface WarningButton{
        class:'warning',
        text1:'修改'
    }
    interface DangerButton{
        class:'danger',
        text2:'删除'
    }
    type Button = WarningButton|DangerButton;
    function getButton(button:Button){
        if(button.class=='warning'){
            console.log(button.text1);
        }
        if(button.class=='danger'){
            console.log(button.text2);
        }
    }
    // 类型字面量+可辨识联合类型
    interface User {
        username: string
    }
    type Action = {
        type:'add',
        payload:User
    } | {
        type: 'delete'
        payload: number
    }
    const UserReducer = (action: Action) => {
      switch (action.type) {
        case "add":
          let user: User = action.payload;
          break;
        case "delete":
          let id: number = action.payload;
          break;
        default:
          break;
      }
    };
}

// 4. in操作符 
namespace d {
    // in 运算符可以被用于参数类型的判断
    interface A { a: number }
    interface B { b: number  }
    function fn ( x : A | B) {
        if( 'a' in x  ) return x.a
        return x.b
    }
}

// 5.自定义的类型保护
// type is Type1Class就是类型谓词
// 谓词为 parameterName is Type这种形式,parameterName必须是来自于当前函数签名里的一个参数名
// 每当使用一些变量调用isType1时，如果原始类型兼容，TypeScript会将该变量缩小到该特定类型
namespace g {
    // function isType1(type: Type1Class | Type2Class): type is Type1Class {
    //     return (<Type1Class>type).func1 !== undefined;
    // }

    interface A { a: number }
    interface B { b: number  }
    function isA (x:A|B):x is A {
        return (<A>x).a ==2
    }
    function getA (x:A|B):any{
        if(isA(x)){
            return x.a
        }
        return x.b
    }
    getA({a:1})
}
// 6.unknown(不知道)类型 全局顶级类型 
// unknown是any类型对应的安全类型
// 可以对any进行任何操作，而不需要检查类型（赋值可以为所欲发）
namespace i {
    // 6.1 任何类型都可以赋值给unknown类型
    let value: unknown;
    value = true;             // OK
    value = 42;               // OK

    // 6.2 unknown类型只能被赋值给any类型和unknown类型本身
    let values: unknown;
    let value1: unknown = values;   // OK
    let value2: any = values;       // OK
    let value3: boolean = values;   // Error

    // 6.3 如果想调用unknown上的方法和属性，缩小 unknown 类型范围
    // 断言 typeof instanceof 自定义类型保护函数 都可以缩小unknown类型范围
    (value1 as string).length

    // 6.4 在联合类型中，unknown 类型会吸收任何类型
    type UnionType1 = unknown | null;       // type UnionType1 = unknown
    type UnionType2 = unknown | undefined;  // type UnionType2 = unknown

    // 6.5 在交叉类型中，任何类型都可以吸收 unknown 类型。
    type IntersectionType1 = unknown & null;       // type IntersectionType1 = null
    type IntersectionType2 = unknown & undefined;  // type IntersectionType2 = undefined
    interface A {name:string,c:number}
    interface B {age:number,c:number}
    type C = A&B
    let c : C = { name:"ikki",age:10,c:10 }

    // 6.6 never是unknown的子类型
    type isNever = never extends unknown ? true : false; //type isNever = true

    // 6.7 keyof unknown 等于never
    type key = keyof unknown //type key = never

    // 6.8 只能对unknown进行等或不等操作，不能进行其它操作
    let un1:unknown;
    let un2:unknown;
    un1 === un2
    // un1 !== un2
    // un1 += un2 // 运算符“+=”不能应用于类型“unknown”和“unknown”。ts(2365)

    // // 6.9 unknown类型不能访问熟悉，不能作为回调函数，不能当作类的构造函数不能创建实例
    // un1.name
    // un1();
    // new un1();

    // 6.10
} 